#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <time.h>
#include <sys/time.h>
#include <sys/mount.h>
#include <cutils/sockets.h>
#include <poll.h>
#include <ctype.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <math.h>
#include <arpa/inet.h>
#include <cutils/properties.h>
#include "camera.h"
#include "platform_config.h"
#include "myjni.h"
#define UPDATE_PATH "/data/local/tmp/update.zip"
#define EXTRACT_TO "/data/local/tmp/update"
#define SYSTEM_CMD_FILE    "/data/local/tmp/update/systemCmd.txt"
int epoll_cmdfd;
volatile int flag_login = 0;
volatile int threadRuning = 1;
static volatile int haveCmdToJava = 0;
volatile int GPS_MJ_START = 0;
static pthread_mutex_t mutex_gpsInfo = PTHREAD_MUTEX_INITIALIZER;
int    threadSocketFd[2];
int threadSocketR, threadSocketW;
void car_power_signal(int signum);
static char car_power_stat = -1;
static int picture_interval = 30;
volatile unsigned int start_deep_work = 0;
static int take_picture_state = -1;
static int tvin_state = 0;
static int take_picture_interval[7] = {0, 30, 60, 120, 180, 240, 300};//开始工作，隔30s,拍第一张，隔1分钟拍第二张，隔2分钟第三张......，5分钟后固定不变;停止工作马上拍一张
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
double sgj_kuandu = 2.5;
extern stru_GPSPOINT *str_gpsPoints; 
extern stru_GPSPOINT *str_PlanarPoints; 
extern stru_GPSPOINT *str_outLinePoints;
extern void *gps_state_init(void *arg);
extern int playMusic(const char *path);
extern volatile int gps_state;
extern inline int read_gps_data(char *path, stru_GPSPOINT *data);
extern int gpsPoints_Index;
//extern int GPS_POINT_Index1;
extern double ShouGeLen;
extern double LengMaxx;
extern double LengMaxy;
extern int fd_gprs;
extern int RawGpsDataIndex;
extern _GPSDATAREG   gpsdata;
extern volatile int ultra_uart_data;
SysInf  SysInfor;
int app_version = 250;
//函数定义区
static stru_GPSPOINT *depth_offline_data;
volatile int ultra_depth = 0, g_depth = 0;
double  cur_lat = 0, cur_lon = 0;
static void generate_zip_pack(void);

static int check_tvin() {
    int fd = open(TVIN_PATH, O_RDONLY);
    if (fd <= 0) {
        LOGE("open %s err[%s]", TVIN_PATH, strerror(errno));
        return -1;
    }
    char val = -1;
    read(fd, &val, sizeof(val));
    close(fd);
    if (val== '1')
        return 1;//tvin insert

    return 0;//tvin unplug
}

void sleepMsec(long long msec)
{
    struct timespec ts;
    int err; 

    ts.tv_sec = (msec / 1000);
    ts.tv_nsec = (msec % 1000) * 1000 * 1000;

    do { 
        err = nanosleep (&ts, &ts);
    } while (err < 0 && errno == EINTR);
}
void sleepUsec(long long usec)
{
    struct timespec ts;
    int err; 

    ts.tv_sec = (usec / 1000000);
    ts.tv_nsec = usec;

    do { 
        err = nanosleep (&ts, &ts);
    } while (err < 0 && errno == EINTR);
}
#define MSG_ID 0x0801
#define PICTURE_DIV 960

struct MSG_PACKAGE_INFO {
    unsigned short package_div_num;
    unsigned short package_id;//start from 1
}__attribute__((packed));

struct MSG_HEAD {
    unsigned short msg_id;
    unsigned short msg_prop;
    unsigned char phone_num[6];
    unsigned short msg_serial_num;//start form 0
    struct MSG_PACKAGE_INFO msg_package_info;
}__attribute__((packed));

struct MEDIA_INFO {
    unsigned int time_stamp;
    unsigned char media_type;
    unsigned char media_format;
    unsigned char event_code;
    unsigned char channel_id;
	u32 device_warning;
	u32 gps_state;
	u32 latitude;
	u32 longtitude;
	u16 altitude;
	u16 speed;
	u16 bearing;
	char time[6];
    //unsigned int package_div_num;
    //unsigned int package_id; //start from 1
    //unsigned char *package_data;
}__attribute__((packed));


struct PICTURE_INFO {
    struct MSG_HEAD msg_head;
    struct MEDIA_INFO media_info;
}__attribute__((packed));

static unsigned char gen_xor(unsigned char *buf, unsigned int len) {
    unsigned char xor = buf[0];
    unsigned int i;    
    for (i = 1; i < len; i++) {
        xor ^= buf[i];
    }

    return xor;
}

int upload_picture(char *path) {
    unsigned int pictureSize = 0;
    unsigned char *sendBuf;
    unsigned int i, len = 0, t_len = 0;
    struct PICTURE_INFO *p_info;
    struct timeval old_tv, tv;
    long timeStamp;
    unsigned short msg_serial_num = 0;
    FILE *fp = fopen(path, "r");
    if (fp == NULL) {
        LOGE("%s open picture err", __func__);
        return -1;
    }
    fseek(fp, 0L, SEEK_END);
    pictureSize = (unsigned int)ftell(fp);
    fseek(fp, 0L, SEEK_SET);
    unsigned char *dataBuf = malloc(1500);
    sendBuf = dataBuf;
    p_info = (struct PICTURE_INFO *)malloc(sizeof(struct PICTURE_INFO));
    memset(p_info, 0, sizeof(struct PICTURE_INFO));
    memset(sendBuf, 0, 1024);
    sendBuf[0] = 0x7e;//数据头标识
    sendBuf++;
    p_info->msg_head.msg_id = htons(MSG_ID);
    char *p_t_id = SysInfor.LocalPhoneNum1; 
    for(i=0; i<6; i++)
    {
        char format[3];
        strncpy(format, p_t_id, 2);
        format[2] = 0;
        int num = atoi(format);
        p_t_id += 2;
        p_info->msg_head.phone_num[i] = (num/10)*16+num%10;
    }
    p_info->msg_head.msg_package_info.package_div_num = htons(pictureSize/PICTURE_DIV + !!(pictureSize%PICTURE_DIV)); //每个包最大960字节

    p_info->media_info.media_type = 0;
    p_info->media_info.media_format = 0;
    p_info->media_info.event_code = 1;
    p_info->media_info.channel_id = 1;
    //p_info->media_info.package_div_num = htonl(pictureSize/PICTURE_DIV + !!(pictureSize%PICTURE_DIV)); 

	p_info->media_info.device_warning = htonl(0);
	p_info->media_info.gps_state = htonl(gps_state);
	p_info->media_info.latitude = htonl(cur_lat * 1000000);
	p_info->media_info.longtitude = htonl(cur_lon * 1000000);
	p_info->media_info.altitude = htons(0);
	p_info->media_info.speed = htons(gps_speed);
	p_info->media_info.bearing = htons(gps_bearing);
	char* Pdata = p_info->media_info.time;
	*Pdata = gps_year % 100;//year
	Pdata++;
	*Pdata = gps_mon % 100;//month
	Pdata++;
	*Pdata = gps_day % 100;//date
	Pdata++;
	*Pdata = gps_hour % 100;//hour
	Pdata++;
	*Pdata = gps_min % 100;//minute
	Pdata++;
	*Pdata = gps_sec % 100; //second
	UTC2China((u8*)p_info->media_info.time);//整理时间格式

    unsigned int info_len = sizeof(struct PICTURE_INFO);
    unsigned char *p_data = sendBuf + info_len;
    unsigned int package_id = 0;
    gettimeofday(&old_tv, NULL);
    int send_err_count = 0;
    timeStamp = old_tv.tv_sec + old_tv.tv_usec/1000;
    p_info->media_info.time_stamp = htonl((unsigned int)timeStamp);
    while (t_len < pictureSize) {
        p_info->msg_head.msg_serial_num = htons(msg_serial_num++);
        len = (pictureSize-t_len) < PICTURE_DIV ? pictureSize-t_len:PICTURE_DIV;
        p_info->msg_head.msg_prop = htons((1<<13)|(len + sizeof(struct MEDIA_INFO)));
        p_info->msg_head.msg_package_info.package_id = htons(package_id);
        //p_info->media_info.package_id = htonl(package_id);
        memcpy(sendBuf, p_info, info_len);
        fread(p_data, 1, len, fp);
        sendBuf[info_len + len] = gen_xor(sendBuf, info_len + len);//校验位
        sendBuf[info_len + len + 1] = 0x7e;//数据尾标识
        int ret = GPRSDataSend((char *)dataBuf, info_len + len + 3, 0, 100);
#if 0
        if (ret > 0) {
            LOGE("发送图片ret[%d]", ret);
            HEX_Print((char *)sendBuf, ret);
            if(send_err_count++ > 3) {
                LOGE("发送失败%d次，放弃", send_err_count);
                break;
            }
            LOGE("发送失败%d次，重新发送", send_err_count);
            continue;
        } else {
            send_err_count = 0;
        }
#endif
        t_len += len;
        //LOGE("id=%u 已发送%u bytes,剩余%u bytes", package_id, t_len, pictureSize-t_len);
        package_id++;
    }
    gettimeofday(&tv, NULL);
    LOGE("耗时 %ld s", (tv.tv_sec + tv.tv_usec / 1000000) - (old_tv.tv_sec + old_tv.tv_usec / 1000000)); 
    write_log_to_sdcard(LOG_TXT_PATH, "上传照片");
	LOGE("上传照片");
    free(p_info);
    free(dataBuf);
    fclose(fp);
    return 0;
}



static void take_picture(void) {
    unsigned int i;
    LOGE("Take picutre");

    if (tvin_state != 1) {
        LOGE("tvin not exist,break");
        return ;
    }
    if (open_camera() == 0) {
        char *yuv422 = malloc(VIDEO_WIDTH*VIDEO_HEIGHT*2);
        int ret = get_picture((u8 *)yuv422);
        close_camera();
        if (ret > 0) {
            char path[128], time_str[128];
            struct tm *p;
            long ts;
            int index;
            char num;
            int remove_flags = 0;
            ts = time(NULL);
            p = localtime(&ts);
            sprintf(time_str, "%d%02d%02d-%02d%02d%02d", (1900+p->tm_year), 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
//            yuv422_to_yuv420p(yuv422, yuv420p, VIDEO_WIDTH, VIDEO_HEIGHT);
#if 0
            static int count = 0;
            char path[48];
            sprintf(path, "/sdcard/yuv%d.yuv", count++);//YUV422格式
            FILE *fp = fopen(path, "wb");
            if (fp == NULL) {
                LOGE("open frame data file failed\n");
                return -1;
            }
            fwrite(data, 1, PICTURE_LENGTH, fp);
            fclose(fp);
#endif

           // sprintf(path, "/mnt/extsd/%s.jpeg", time_str);
            FILE *fp;
            //fp = fopen(path, "wb");
            //if (!fp) {
            //    LOGE("SD card not exist,try usb");
            //    sprintf(path, "/mnt/usbhost1/%s.jpeg", time_str);
            //    fp = fopen(path, "wb");
            //    if (!fp) {
            //        LOGE("USB not exist, save to internal sdcard");
            sprintf(path, "/sdcard/%s.jpeg", time_str);
            //        remove_flags = 1;
            //fp = fopen(path, "wb");
            //if (!fp) {
            //    LOGE("open %s error[%s], quit", path, strerror(errno));
            //    return ;
            //}
            //  }
           // }
            sprintf(time_str, "%d-%02d-%02d% 02d:%02d:%02d", (1900+p->tm_year), 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);

            //getGpsInfo();
#if 1
            int x_offset;
            addWaterMark((u8 *)yuv422, VIDEO_HEIGHT/50, VIDEO_WIDTH, VIDEO_HEIGHT, time_str);
            sprintf(time_str, "J:%f", cur_lon);
            addWaterMark((u8 *)yuv422, VIDEO_HEIGHT/50 + 25, VIDEO_WIDTH, VIDEO_HEIGHT, time_str);
            sprintf(time_str, "W:%f", cur_lat);
            addWaterMark((u8 *)yuv422, VIDEO_HEIGHT/50 + 50, VIDEO_WIDTH, VIDEO_HEIGHT, time_str);
#endif
            //if (fp) {
            //    fclose(fp);
            yuv420p_to_jpeg(path, yuv422, VIDEO_WIDTH, VIDEO_HEIGHT, 100);  
            sync();
            LOGE("Save piucture success");
            if (flag_login) {//在线才上传照片
                report_locat(start_deep_work, (g_depth+5)/10);
                upload_picture(path);
            }
            //  if (remove_flags)
            remove(path);
            //}
        }
        free(yuv422);
    } else {
        LOGE("Fail to open camera!");
    }
}


#define ID_UPDATE_QUERY     0x0108  //查询升级包
#define ID_UPDATE_ISSUED    0X8108  //下发升级包信息
#define ID_UPDATE_REQUEST   0x0108  //请求升级包
#define ID_UPDATE_DOWNLOAD  0X8108  //下发升级包数据

#define UPDATE_TYPE 2 //1收割机 2深松机设备

#define UPDATE_SUCCESS 0
#define UPDATE_ERROR   1
#define UPDATE_CANCEL  2
#define UPDATE_REQUEST 3
#define UPDATE_QUERY  4

struct msg_pack_info {
    unsigned short div_num;//分包总数
    unsigned short id;//分包id号,start from 1
}__attribute__((packed));


struct  q_result_data {
    unsigned char type;
    unsigned char vendor[5];
    unsigned char version[5];
    unsigned int package_len;
}__attribute__((packed));


struct  respond_data {
    unsigned short div_num;
    unsigned short id;
}__attribute__((packed));

struct msg_head {
    unsigned short id; //类型，升级查询为0x0108
    unsigned short prop;//结构体struct query_data的大小，这里为2
    unsigned char phone_num[6];//手机号码如018618816002
    unsigned short serial_num;//序列号，这里为0
}__attribute__((packed));

struct  query_data {
    unsigned char type;//类型， 如 1收割机 2深松机设备 等等
    unsigned char result;//类型，升级查询，这里为4
}__attribute__((packed));


struct update_query {
    struct msg_head head;
    struct query_data data;
}__attribute__((packed));

struct query_result {
    struct msg_head head;
    struct q_result_data data;
}__attribute__((packed));


struct request_result {
    struct msg_head head;
    struct msg_pack_info pack;//请求返回打包数据，所以有该项
    struct q_result_data data;
}__attribute__((packed));



static unsigned int  data_checkout(unsigned char *src, unsigned int len) {
    unsigned int i =0, j = 0;
    unsigned char *dest = (unsigned char *)malloc(len);

    if (len < 1)
        return 0;
    dest[j++] = src[0];
    for (i = 1; i < len - 1; i++) {
        if (src[i] == 0x7d) {
            if (src[i+1] == 0x01) {
                dest[j++] = 0x7d;
                i++;
            } else if (src[i+1] == 0x02) {
                dest[j++] = 0x7e;
                i++;
            }
        } else {
            dest[j++] = src[i]; 
        }
    }
    dest[j++] = src[len-1];
    memcpy(src, dest, j);
    free(dest);

    return j;
}
#define QUERY_ERR -1
#define QUERY_NEW_VERSION 0
#define QUERY_NOTHING 1
static int updateQuery(unsigned int *V) {
    unsigned char data[128];
    int i, len, t_len = 0;
    struct update_query query;
    unsigned short serial_num = 0;
    unsigned char *sendBuf = data;

    sendBuf[0] = 0x7e;//数据头标识
    sendBuf++;

    query.head.id = htons(ID_UPDATE_QUERY);
    query.head.prop = htons(sizeof(struct query_data));
    char *serial = SysInfor.LocalPhoneNum1; 
    for(i=0; i<6; i++)
    {
        char format[3];
        strncpy(format, serial, 2);
        format[2] = 0;
        int num = atoi(format);
        serial += 2;
        query.head.phone_num[i] = (num/10)*16+num%10;
    }
    query.head.serial_num = htons(serial_num);
    //query.head.pack.div_num = htons(0);
    //query.head.pack.id = htons(0);
    query.data.type = UPDATE_TYPE;
    query.data.result = UPDATE_QUERY;

    memcpy(sendBuf, &query, sizeof(query));
    sendBuf[sizeof(query)] = gen_xor(sendBuf, sizeof(query));//校验位
    sendBuf[sizeof(query) + 1] = 0x7e;//数据尾标识
    len = 0;
    i = 0;
    LOGE("升级查询 发送内容%dbyte:", sizeof(query)+3);
    len = GPRSDataSend((char *)data, sizeof(query) + 3, 10000000, 127);
    if (len <= 0) {
        LOGE("发送升级查询失败");
        return QUERY_ERR;
    }
    LOGE("查询升级包返回:%d", len);
    if (len < 2)
        return QUERY_ERR;
    HEX_Print((char *)data, len);
    len = data_checkout((unsigned char *)data, (unsigned int)len);
    LOGE("查询转义:%d", len);
    if (gen_xor((unsigned char *)data + 1, len-3) != data[len-2]) {
        LOGE("校验失败");
        return QUERY_ERR;
    }
    struct query_result q_result;
    char *p = (char *)data;
    p++;
    memcpy(&q_result, p, sizeof(q_result));
    q_result.head.serial_num = ntohs(q_result.head.serial_num);
    q_result.data.package_len = ntohl(q_result.data.package_len);
    LOGE("流水号:%d", q_result.head.serial_num);
    LOGE("厂商号:");
    CHAR_Print((char *)q_result.data.vendor, sizeof(q_result.data.vendor));
    LOGE("版本号:");
    CHAR_Print((char *)q_result.data.version, sizeof(q_result.data.version));
    LOGE("数据包长度:%d", q_result.data.package_len);
    char version[6];
    memset(version, 0, sizeof(version));
    memcpy(version, q_result.data.version + 1, 4);
    unsigned int ver = (unsigned int)(atof(version)*100);
    *V = (unsigned int)ver;
    //if (ver > SysInfor.version) {
	if (ver > app_version) {
        LOGE("检测到新版本：%d,原版本:%d", ver, app_version);
        return QUERY_NEW_VERSION;
    }
    LOGE("当前已是最新版本");
    return QUERY_NOTHING;
}

static int update_err_count = 0; 
struct update_package_info {
    char *data;
    unsigned int len;
};
extern int socket_cli;
static int updateRequest(struct update_package_info *package1, int *packageNum) {
    unsigned char *sendBuf;
    unsigned int i, t_len = 0;
    unsigned long len;
    struct update_query query;
    unsigned short serial_num = 0;
    struct query_result q_result;
    struct timeval tv1, tv2;
    unsigned char dataSend[128];
    //app_info info;
    //info.bit = BIT_APP_UPDATE_PROGRESS;
    //info.data = -1;
    sendBuf = dataSend;
    sendBuf[0] = 0x7e;//数据头标识
    sendBuf++;

    gettimeofday(&tv1, (struct timezone *) NULL);
    query.head.id = htons(ID_UPDATE_QUERY);
    query.head.prop = htons(sizeof(struct query_data));
    char *serial = SysInfor.LocalPhoneNum1; 
    for(i=0; i<6; i++)
    {
        char format[3];
        strncpy(format, serial, 2);
        format[2] = 0;
        int num = atoi(format);
        serial += 2;
        query.head.phone_num[i] = (num/10)*16+num%10;
    }
    query.head.serial_num = htons(serial_num);
    //query.head.pack.div_num = htons(0);
    //query.head.pack.id = htons(0);
    query.data.type = UPDATE_TYPE;
    query.data.result = UPDATE_REQUEST;

    memcpy(sendBuf, &query, sizeof(query));
    sendBuf[sizeof(query)] = gen_xor(sendBuf, sizeof(query));//校验位
    sendBuf[sizeof(query) + 1] = 0x7e;//数据尾标识
    len = 0;
    i = 0;
    LOGE("升级请求 发送内容%dbyte:", sizeof(query)+3);
    HEX_Print((char *)dataSend, sizeof(query) + 3);
    int ret = GPRSDataSend((char *)dataSend, sizeof(query) + 3, 0, 127);
    //if (ret <= 0) {
   //     LOGE("发送升级请求失败");
    //    return -1;
   // }
    len = 0;
    i = 0;
    char *pack_data = malloc(1024*1024*5);
    int count = 0;
    int head_count = 0;
    //int read_flags = 1;
    int timeout_count = 0;
    struct request_result result;
    unsigned int head_len = sizeof(struct request_result);
    int flags = 1;
#if 0
    while (1) {
        nevents = epoll_wait(epoll_uartfd, &events, 1, 10000);
        if ((nevents > 0) && ((events.events & EPOLLIN) != 0)) {
            count = read(fd_gprs, pack_data + len, 2000);
            if (count > 0) {
                len += count;
                if (flags && (update_err_count==0) && (len>head_len)) {
                    flags = 0;
                    memcpy(&result, pack_data + 1, head_len);
                    result.pack.div_num = ntohs(result.pack.div_num);
                    result.pack.id = ntohs(result.pack.id);
                    package_size = 2*1024*1024;//result.pack.div_num*1042;
                    //LOGE("package_size=%d", package_size);
                }
            }
        } else {
            LOGE("uart timeout");
            break;
        }
    }
#endif
    while (socket_cli != -1) {
        fd_set readfds;
        struct timeval tv;
        FD_ZERO(&readfds);
        FD_SET(socket_cli, &readfds);
        tv.tv_sec = 10;
        tv.tv_usec = 0;
        ret = select(socket_cli + 1, &readfds, NULL, NULL, &tv); //阻塞,err:0 timeout err:-1 错误见errno
        if (ret > 0 && FD_ISSET(socket_cli, &readfds)) {
            if (len >= 1024*1023*5)
                break;
            count = read(socket_cli, pack_data + len, 1024);
            if (count > 0) {
                len += count;
                LOGE("download total=%lu, count =%d", len, count);
                if (flags && (len>head_len)) {
                    flags = 0;
                    memcpy(&result, pack_data + 1, head_len);
                    result.pack.div_num = ntohs(result.pack.div_num);
                    result.pack.id = ntohs(result.pack.id);
                }

            } else {
                LOGE("socket recv unknown err[%s]", strerror(errno));
                break;
            }
        } else {
            LOGE("ret=%d, select timeout err=%s", ret, strerror(errno));
            if (errno == ECONNRESET || errno == EPIPE) {
                socket_cli = -1;
            }
            break;
        }
    }

    unsigned int j = 0;
    char *p = pack_data; 
    int error_count = 0, success_count = 0;
    for (i = 0; i < len; i++) {
        p[j++] = pack_data[i];
        if ((pack_data[i] == 0x7e) && (++head_count % 2 == 0)) {
            count = data_checkout((unsigned char *)p, j);
            unsigned char xor = gen_xor((unsigned char *)p + 1, count - 3); 
            if ( xor != *(p + count - 2)) {
                LOGE("校验失败 id=%d, len=%d", head_count/2, count);
                error_count++;
            } else {
                memcpy(&result, p + 1, head_len);
                result.pack.div_num = ntohs(result.pack.div_num);
                result.pack.id = ntohs(result.pack.id);
                if (xor == *(p + 1 + head_len + result.data.package_len)) {//这里还要校验一次，有可能数据中夹带有00等其他干扰数据
                    memcpy(package1[result.pack.id-1].data, p, count);
                    *packageNum = result.pack.div_num;
                    package1[result.pack.id-1].len = count;
                    success_count++;
                  //  LOGE("校验成功");
                } else {
                    LOGE("二次校验失败 id=%d", result.pack.id);
                    error_count++;
                }
                //LOGE("head_len=%d, count=%d package_len=%d", head_len, count, result.data.package_len);
            }
            j = 0;
        }
    }
    gettimeofday(&tv2, (struct timezone *) NULL);
    LOGE("下载完成，校验错误包:%d个, 耗时:%lu分%lu秒", error_count, SEC_DIFF(tv1, tv2)/60, SEC_DIFF(tv1, tv2)%60);
    free(pack_data);

    return error_count;
}

static int extract_update_package(void) {
    system("mkdir /data/local/tmp/update");
    if (unzip(UPDATE_PATH, NULL, NULL, EXTRACT_TO)) {
        LOGE("解压升级包失败");
        return -1; 
    }   
    system("chmod -R 777 /data/local/tmp/update");
    sync();
    char md5Val[33];
    char md5Buf[256];
    int md5CheckResult = 0;

    int ret = Compute_file_md5("/data/local/tmp/update/uartService", md5Val);
    if (ret != 0) {
        LOGE("compute MD5 fail");
        return -1;
    }
    LOGE("update packge MD5:%s", md5Val);
    FILE *fp = fopen("/data/local/tmp/update/MD5.txt", "r");
    if (!fp) {
        LOGE("open MD5.txt fail[%s]", strerror(errno));
        return -1;
    }
    while (fgets(md5Buf, sizeof(md5Buf), fp)) {
        if (strstr(md5Buf, md5Val)) {
            LOGE("MD5 check ok");
            md5CheckResult = 1;
            break;
        }
    }
    fclose(fp);
    if (md5CheckResult == 0)
        return -1;
    write_gps_info("MD5校验通过"); 
    remount_system(MS_REMOUNT);
    system("rm /system/bin/uartService; cp /data/local/tmp/update/uartService /system/bin/;chmod 755 /system/bin/uartService");
    if (access("/data/local/tmp/update/SystemCmd.txt", F_OK) == 0) {
        systemCmd("/data/local/tmp/update/SystemCmd.txt");
    }
    system("busybox rm /data/local/tmp/update* -rf; sync");
    write_gps_info("升级成功，重启");
    system("reboot");
    return 0;
}


static void sendDepthAndWeigth() {
    u8 gprsSendIsSuccess;

    gprsSendIsSuccess = SendAreaAndWeight();
    if (gprsSendIsSuccess == 0) {
    } else if (gprsSendIsSuccess == SUCCESS) {
        update_offline_data_tail(MU_CHAN_PATH);
        LOGE("Send area and depth data success");
        write_log_to_sdcard(LOG_TXT_PATH, "发送面积成功");
        write_gps_info("发送面积成功");
    } else {
        LOGE("Send area and depth data fail, retry again!");
        write_log_to_sdcard(LOG_TXT_PATH, "发送面积失败");
        write_gps_info("发送面积失败");
    }
}


static int offline_delay_count = 0;
//补传油耗，上报位置信息，心跳，终端注册鉴权
void *SupplementOilAndReportLocation (void * arg) {
    struct timeval g_tv = {.tv_sec = 0, .tv_usec = 0}, 
                   offline_tv = {.tv_sec = 0, .tv_usec = 0}, area_tv = {.tv_sec = 0, .tv_usec = 0}, 
                   locat_tv = {.tv_sec = 0, .tv_usec = 0}, plus_tv = {.tv_sec = 0, .tv_usec = 0}, picture_tv = {.tv_sec = 0, .tv_usec = 0};
    int i;
    int update_check = 1, update_check_count = 0;
    int msec, ret;
    unsigned int version = 0;
    int query_err_count = 0;
    int packageNum = -1; 
    struct update_package_info *package1;
    int success_count = 0;
    int start_deep_work_temp = 0;
    unsigned long gps_auto_calc_state = 0, start_deep_work_state = 0;
    package1 = (struct update_package_info *)malloc(3500*sizeof(struct update_package_info));
    for (i = 0; i < 3500; i++) {
        package1[i].data = (char *)malloc(2000);
        memset(package1[i].data, 0, 2000);
        package1[i].len = 0;
    }   

    while (socket_init() == -ENETUNREACH) {
        sleepMsec(1000);
    }
    while(threadRuning) {
        gettimeofday(&g_tv, (struct timezone *) NULL);
        if (!start_deep_work && g_depth>100 && gps_speed>1)
            gps_auto_calc_state++;
        else
            gps_auto_calc_state = 0;
        if (start_deep_work)
            start_deep_work_state++;
        else
            start_deep_work_state = 0;
        if (start_deep_work_state==5 || gps_auto_calc_state==5) {//自动计亩开始后也要上传照片
            take_picture_state  = 1;
            picture_tv = g_tv;
        }else if (start_deep_work_state==0 && gps_auto_calc_state==0) {//手动测亩结束,如果机器没停下来还继续上报?
            take_picture_state  = 0;
        }

        if(0 == flag_login) {//系统未注册
            if(abs(SEC_DIFF(g_tv, offline_tv)) >= 10) {
                LOGE("offline, duration:%ld seconds", SEC_DIFF(g_tv, offline_tv));
                offline_tv = g_tv;
                LoginAndAuthentication();
            }
        } else {   //在线
            if (update_check) {
                ret = updateQuery(&version);
                if (ret == QUERY_NOTHING) {
                    update_check = 0;
                } else if (ret == QUERY_ERR) {
                    query_err_count++;
                } else if (ret == QUERY_NEW_VERSION) {
                    updateRequest(package1, &packageNum);
                    LOGE("packageNum=%d", packageNum);
                    success_count = 0;
                    for (i = 0; (i < packageNum)&&(packageNum < 3500); i++) {
                        unsigned char *p = (unsigned char *)package1[i].data;
                        int len = package1[i].len;
                        struct request_result result;
                        int head_len = sizeof(struct request_result);
                        //HEX_Print((char *)p, len);
                        if (len < head_len) {
                            LOGE("[%d]数据小于 head_len", i);
                            continue;
                        }
                        success_count++;
                    }
                    if (success_count == packageNum) {
                        LOGE("下载升级包成功，开始升级");
                        write_gps_info("下载升级包成功，开始升级");
#if 1
                        if (access(UPDATE_PATH, F_OK)) {
                            creat(UPDATE_PATH, S_IRWXO);
                            chmod(UPDATE_PATH, S_IROTH|S_IWOTH|S_IRGRP|S_IWGRP|S_IRWXU|S_IRWXO|S_IRWXG);
                        }
                        int update_fd = open(UPDATE_PATH, O_RDWR);
                        if (update_fd < 0) {
                            LOGE("open %s err[%s]", UPDATE_PATH, strerror(errno));
                            update_check = 0;
                        }
                        /* 清空文件 */
                        ftruncate(update_fd, 0);
                        /* 重新设置文件偏移量 */
                        lseek(update_fd, 0, SEEK_SET);
                        for (i = 0; i < packageNum; i++) {
                            unsigned char *p = (unsigned char *)package1[i].data;
                            int len = package1[i].len;
                            int head_len = sizeof(struct request_result);
                            write(update_fd, p + 1 + head_len, len - 3 - head_len);
                        }
                        close(update_fd);
#endif
                        if(extract_update_package() == 0) {
                            update_check = 0;
                            //info.bit = BIT_APP_UPDATE_PROGRESS;
                            //info.data = 101;
                            //update_app_info(&info);
                        } else {
                            update_err_count = 3;
                        }
                    } else {
                        update_err_count++;
                    }
                }
                if (update_err_count > 2) {
                    LOGE("升级失败,错误个数 %d,退出", packageNum - success_count);
                    //info.bit = BIT_APP_UPDATE_PROGRESS;
                    //info.data = -1;
                    //update_app_info(&info);
                    update_check = 0;
                }
                if(query_err_count > 10) {
                    LOGE("检测升级包失败,退出");
                    //info.bit = BIT_APP_UPDATE_PROGRESS;
                    //info.data = -1;
                   // update_app_info(&info);
                    update_check = 0;
                }

                if (!update_check) {
                    for (i = 0; i < 3500; i++)
                        free(package1[i].data);
                    free(package1);

                }

            }

            if (abs(SEC_DIFF(g_tv, area_tv)) >= 3) {
                area_tv = g_tv;
                sendDepthAndWeigth(); 
            }

            if(abs(SEC_DIFF(g_tv, locat_tv)) >= ((start_deep_work || (g_depth>100 && gps_speed>1)) ? 6 : 30)) {
                locat_tv = g_tv;
                if(0 == report_locat(start_deep_work, (g_depth+5)/10)) {//这里要上传的单位是cm,加5是为了4舍5入
                    offline_delay_count++;
                    LOGE("Send loation error, err count:%d", offline_delay_count);
                    if ( offline_delay_count > 4) {
                        flag_login = 0;
                        offline_delay_count = 0;
                    }
                } else {
                    offline_delay_count = 0;
                    LOGE("Send loaction success!");
                }

            }

            if(abs(SEC_DIFF(g_tv, plus_tv)) >= 30) {
                plus_tv = g_tv;
                if (1 == plus())
                    LOGE("Send plus success");
                else
                    LOGE("Send plus fail!");
            }
            if((take_picture_state>0) && (abs(SEC_DIFF(g_tv, picture_tv))>=take_picture_interval[take_picture_state])) {
                LOGE("take_picture_state=%d,time=%d", take_picture_state, abs(SEC_DIFF(g_tv, picture_tv)));
                if (take_picture_state < (int)(ARRAY_SIZE(take_picture_interval)-1))
                    take_picture_state++;
                picture_tv = g_tv;
                take_picture();
            } else if (take_picture_state == 0) {
                picture_tv = g_tv;
                sendDepthAndWeigth(); 
                //take_picture(picture_data);
                take_picture_state = -1;
            }
        }
        sleepMsec(10);
    }
    LOGE("线程%s退出", __func__);
    return NULL;
}

#define SOCKET_NAME "uartService"
void *read_para(void * arg)
{

    struct sockaddr addr;
    socklen_t alen;
    int lsocket, s;
    char buf[256] = {0};
    char info[256];
    LOGE("read para thread create");
    
    lsocket = android_get_control_socket(SOCKET_NAME);
    if (lsocket < 0) {
        LOGE("Failed to get socket from environment: %s\n", strerror(errno));
        return NULL;
    }
    if (listen(lsocket, 5)) {
        LOGE("Listen on socket failed: %s\n", strerror(errno));
        return NULL;
    }

    for (;;) {
        alen = sizeof(addr);
        LOGE("socket ready...");
        memset(info, 0, sizeof(info));
        sprintf(info, "%s:%d;%s;%s;%d;%d;%.1f;%d;%d", SysInfor.IP, SysInfor.port, SysInfor.terminalID, SysInfor.CarNumber_utf8, SysInfor.depth,
                SysInfor.ref_depth, SysInfor.machine_width, SysInfor.angle, SysInfor.a_sensor_height);
        property_set("rw.uartservice.mms.info", info);
        s = accept(lsocket, &addr, &alen);
        if (s < 0) {
            LOGE("Accept failed: %s\n", strerror(errno));
            sleepMsec(1000);
            continue;
        } else {
            struct pollfd fds;
            int nr; 
            int check_count;
            bzero(buf, sizeof(buf));
            fds.fd = s; 
            fds.events = POLLIN;
            fds.revents = 0;
            nr = poll(&fds, 1, 1000);
            LOGE("poll in");
            read(s, buf, sizeof(buf));
            if (strncmp("sd_para", buf, 7) == 0) {
                check_count = 0;
                while (check_count++ < 20) {
                    sleepMsec(100);
                    if (access("/storage/sdcard1/a3e06235-d5cf-413f-868e-bea435693fc5", F_OK) == 0) {
                        LOGE("工厂生产测试开始");
                        write_log_to_sdcard(LOG_TXT_PATH, "工厂生产测试开始");
                        threadRuning = 0;
                        break;
                    }
                    if(checkExFile() > 0)
                        break;
                }
            } else if (strncmp("gsm_ccid", buf, 8) == 0) {
                LOGE("%s", buf);
                strncpy(SysInfor.ccid, buf + 9, sizeof(SysInfor.ccid));
            } else if (strncmp("mms_para", buf, 8) == 0) {
                //LOGE("%s", buf);
                split(buf + 9);
            }
            BlockWrite((char *)&SysInfor, SysInfLength, SYSINFO_SET);
        }
    }

    return NULL;
}

static enum { DEPTH_INVALID = 0, POSITIONED, SENSOR_ERR, UNPOSITIONED, ULTRA_OK, ANGLE_OK, TEST_START, TEST_OK, GPS_ERROR, NETWORK_ERROR, CAMERA_ERROR, ULTRA_ERROR} CMD;
static unsigned int playMusic_CMD[12] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb}; 


static void play_music(unsigned int id) {
    switch (id) {
        case 0xf0:
            playMusic("/system/media/depth_invalid.wav");
            break;
        case 0xf1:
            playMusic("/system/media/positioned.wav");
            break;
        case 0xf2:
            playMusic("/system/media/sensor_err.wav");
            break;
        case 0xf3:
            playMusic("/system/media/unpositioned.wav");
            break;
        case 0xf4:
            playMusic("/system/media/ultra_ok.wav");
            break;
        case 0xf5:
            playMusic("/system/media/angle_ok.wav");
            break;
        case 0xf6:
            playMusic("/system/media/test_start.wav");
            break;
        case 0xf7:
            playMusic("/system/media/test_ok.wav");
            break;
        case 0xf8:
            playMusic("/system/media/test_gps_error.wav");
            break;
        case 0xf9:
            playMusic("/system/media/test_4g_error.wav");
            break;
        case 0xfa:
            playMusic("/system/media/test_camera_error.wav");
            break;
        case 0xfb:
            playMusic("/system/media/test_ultra_error.wav");
            break;
    }

}

void *thread_play_music(void * arg) {
#if 0
    char gps_str[128];
    struct timeval g_tv = {.tv_sec = 0, .tv_usec = 0}, tv = {.tv_sec = 0, .tv_usec = 0};
    gettimeofday(&tv, NULL);
    for (;;) {
        gettimeofday(&g_tv, NULL);
        if (start_deep_work && (abs(SEC_DIFF(tv, g_tv)) >= 10)) {
            tv = g_tv;
            getGpsInfo();
            struct tm *p;
            long ts;
            ts = time(NULL);
            p = localtime(&ts);
            sprintf(gps_str, "%d-%02d-%02d %02d:%02d:%02d    ", (1900+p->tm_year), 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
            strcat(gps_str, cur_lat+2);
            strcat(gps_str, "    ");
            strcat(gps_str, cur_lng+2);
            strcat(gps_str, "\r\n");
            write_gps_info(gps_str, strlen(gps_str));
        }
        sleepMsec(1000);
    }
#endif
    struct epoll_event  ev;
    int epoll_fd = epoll_create(1);
    int nevents, ret;
    unsigned int id[100];
    unsigned int prev_id, play_id;
    int i;
    ev.events  = EPOLLIN;
    ev.data.fd = threadSocketR;
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, threadSocketR, &ev);

    for (;;) {
        prev_id = -1;
        nevents= epoll_wait(epoll_fd, &ev, 1, -1);
        if (nevents < 0) {
            if (errno != EINTR)  
                LOGE("epoll_wait() unexpected error: %s", strerror(errno));
            continue;
        }
        if ((ev.events & EPOLLIN) != 0) {
            ret = read(threadSocketR, id, sizeof(id))/sizeof(unsigned int);
            if (ret > 0) {
                for (i = 0; i < ret; i++) {
                    if (prev_id == id[i])
                        continue;
                    play_music(id[i]);
                    prev_id = id[i];
                }
            }
        }
    }

    return NULL;
}
static int totalDepthCount = 0;
static double dArea = 0;
static double walk_area = 0;
extern double autoMuDistance;
void startDeepWorkInit() {
     gpsPoints_Index=0;
     //GPS_POINT_Index1=0;
     RawGpsDataIndex = 0;
     LengMaxx = 0;
     LengMaxy = 0;
     totalDepthCount = 0;
     autoMuDistance = 0;//清除总距离
}

void autoCalArea(int distance) {
    int i;
    int  validDepthCount = 0, depthSum = 0, depthAvarage = 0;
    unsigned short depth_avarage = 0;
    double depth_rate = 0;
    struct timeval tv1, tv2;
    unsigned short depth_temp = 0;
    unsigned short depthRate_temp = 0; 

    double walk_area = ((double)((distance*SysInfor.machine_width*1.2)/666.67*1000))/1000.0;
    LOGE( "自动计亩 深度数据:%d条", totalDepthCount);
    for (i = 0; i < totalDepthCount; i++) {
        if (depth_offline_data[i].depth >= SysInfor.depth)
            validDepthCount++;
        depthSum += depth_offline_data[i].depth; 
        //LOGE("[%d],depth=%d", i, depth_offline_data[i].depth);
    }
    if (totalDepthCount > 0) { 
        depth_avarage = depthSum/totalDepthCount;
        depth_rate = validDepthCount * 100 / totalDepthCount;
    }
    depth_temp = depth_avarage;
    depthRate_temp = (unsigned short)depth_rate*10;

    LOGE("\r\n自动计亩\r\n行进面积(亩):%.2f"
            "\r\n面积合格率:%.2f%% \r\n深松机宽度(米):%f\r\n默认深度(毫米):%d"
            "\r\n零点参考深度(毫米):%d\r\n平均深度(毫米):%d\r\n深度采样点数:%d\r\n深度采样合格点数:%d\r\n深度合格率:%.2f%%",
            walk_area, 100.0, SysInfor.machine_width, SysInfor.depth, SysInfor.ref_depth, depth_avarage, totalDepthCount, validDepthCount, depth_rate);

    //if (walk_area > 0.3)
    //    save_offline_data(MU_CHAN_PATH, (unsigned int)(walk_area*1000), 1000, depth_temp, depthRate_temp | AUTO_CALC_AREA); //深度合格率的最高位用来区分自动，手动计算亩数
    write_gps_info("手机号:%s\r\n车牌号:%s\r\n终端号:%s \r\n默认深度(毫米):%d \r\n参考深度（毫米）:%d\r\n深松机宽度（米）:%.2f",
            SysInfor.LocalPhoneNum1, SysInfor.CarNumber_utf8, SysInfor.terminalID, SysInfor.depth, SysInfor.ref_depth, SysInfor.machine_width);
    write_gps_info("自动计亩 面积（亩）:%.2f\r\n面积合格率:%.2f%%\r\n平均深度（毫米）:%d\r\n深度合格率:%.2f%%\r\n", 
            walk_area, 100.0, depth_avarage, depth_rate);
    generate_zip_pack();
    startDeepWorkInit();
    sync();
}

static void manualCalAreaAndDeep(void) {
    int i;
    int validDepthCount = 0, depthSum = 0, depthAvarage = 0;
    unsigned short depth_avarage = 0;
    double area_rate = 0;
    double depth_rate = 0;
    struct timeval tv1, tv2;
    int gps_valid_len = 0;
    unsigned int area_temp = 0;
    unsigned short areaRate_temp = 0;
    unsigned short depth_temp = 0;
    unsigned short depthRate_temp = 0; 

    LOGE("手动计亩 gps数据:%d条", gpsPoints_Index);
    LOGE( "手动计亩 深度数据:%d条", totalDepthCount);
    for (i = 0; i < totalDepthCount; i++) {
        if (depth_offline_data[i].depth >= SysInfor.depth)
            validDepthCount++;
        depthSum += depth_offline_data[i].depth; 
        //LOGE("[%d],depth=%d", i, depth_offline_data[i].depth);
    }
    gettimeofday(&tv1, (struct timezone *) NULL);
  //  double glArea = CalAreaProcess(&gps_valid_len);
	LOGE("宽度：%f", SysInfor.machine_width);
	double glArea  = CalAreaInManual(str_gpsPoints, gpsPoints_Index, str_PlanarPoints, SysInfor.machine_width*100);

    gettimeofday(&tv2, (struct timezone *) NULL);
    LOGE("计算面积耗时:%u秒", abs(SEC_DIFF(tv1, tv2)));
    dArea = glArea;//保留3位小数点
 //   double walk_area = ((double)((gps_valid_len*SysInfor.machine_width)/666.67*1000))/1000.0;
	walk_area  = getAreaOfMoving(str_PlanarPoints, gpsPoints_Index, SysInfor.machine_width*100);
    if (dArea > 0)
        area_rate = walk_area * 100 / dArea; 
    if (area_rate > 100)
        area_rate = 100;
    if (totalDepthCount > 0) { 
        depth_avarage = depthSum/totalDepthCount;
        depth_rate = validDepthCount * 100 / totalDepthCount;
    }
    area_temp = (unsigned int)(dArea*1000);
    areaRate_temp = (unsigned short)area_rate*10;
    depth_temp = depth_avarage;
    depthRate_temp = (unsigned short)depth_rate*10;

    LOGE("\r\n手动计亩\r\n总面积(亩):%.2f\r\n行进面积(亩):%.2f"
            "\r\n面积合格率:%.2f%% \r\n深松机宽度(米):%f\r\n默认深度(毫米):%d"
            "\r\n零点参考深度(毫米):%d\r\n平均深度(毫米):%d\r\n深度采样点数:%d\r\n深度采样合格点数:%d\r\n深度合格率:%.2f%%",
            dArea, walk_area, area_rate, SysInfor.machine_width, SysInfor.depth, SysInfor.ref_depth, depth_avarage, totalDepthCount, validDepthCount, depth_rate);

    save_offline_data(MU_CHAN_PATH, area_temp, areaRate_temp, depth_temp, depthRate_temp | MANUAL_CALC_AREA); //深度合格率的最高位用来区分自动，手动计算亩数
    write_gps_info("手机号:%s\r\n车牌号:%s\r\n终端号:%s \r\n默认深度(毫米):%d \r\n参考深度（毫米）:%d\r\n深松机宽度（米）:%.2f",
            SysInfor.LocalPhoneNum1, SysInfor.CarNumber_utf8, SysInfor.terminalID, SysInfor.depth, SysInfor.ref_depth, SysInfor.machine_width);
    write_gps_info("手动计亩 面积（亩）:%.2f\r\n面积合格率:%.2f%%\r\n平均深度（毫米）:%d\r\n深度合格率:%.2f%%\r\n", 
            dArea, area_rate, depth_avarage, depth_rate);
    sync();
}


static void CalAreaAndDeep(int used_offline_data) {
    if (used_offline_data) {
        gpsPoints_Index = read_gps_data(GPS_DATA_PATH, str_gpsPoints);
        totalDepthCount = read_gps_data(DEPTH_DATA_PATH, depth_offline_data);
    }
    if (gpsPoints_Index > 20) {
        LOGE("gps离线数据[%d]大于20条，计算并上传", gpsPoints_Index);
        manualCalAreaAndDeep();
    } else {
        LOGE("gps离线数据[%d]小于20条，删除", gpsPoints_Index);
        write_gps_info("gps离线数据[%d]小于20条，不计算面积", gpsPoints_Index);
    }
    clean_gps_data(GPS_DATA_PATH);
    clean_gps_data(DEPTH_DATA_PATH);
    startDeepWorkInit();//计算完成后初始化一次，有可能接下来会进入自动计亩
}

static void generate_zip_pack(void) {
    char TARGET_PATH[128];
    int argc = 9;
    char *argv[9] = {"minizip", "-o", "-0", "-9", "-p", "3699", "-j", TARGET_PATH, GPS_DATA_LOG_PATH};
    FILE *fp; 
    long len = 0;
    long max_len = 50*1024*1024; 
    
    sync();
    fp = fopen(GPS_DATA_LOG_PATH, "r");
    if (fp) {
        fseek(fp, 0L, SEEK_END);
        len = ftell(fp);
        LOGE("gpsData len=%ld", len);
        fclose(fp);
    }
    if (len > max_len)
        sprintf(TARGET_PATH, "/storage/sdcard1/%sbak.zip", SysInfor.terminalID);
    else
        sprintf(TARGET_PATH, "/storage/sdcard1/%s.zip", SysInfor.terminalID);

    fp = fopen(TARGET_PATH, "wb");
    if (fp) {
        fclose(fp);
        minizip(argc, argv);
        LOGE("写入压缩文件%s", TARGET_PATH);
        if (len > max_len)//确认外部sd卡存在的情况下才删除源文件
            remove("data/local/tmp/gpsData.txt");
    }
    sync();
}


#define CONTINUE_WORK "按键状态[工作]，继续采集数据\r\n"
void *function_key_state(void * arg) {
    int val = 0;
    int i;
    char time_str[128];
    int gps_unposition_count = 0;
    struct tm *tm;
    long ts;
    unsigned int num = 0;
    startDeepWorkInit();
    val = read_gpio(FUNCTION_KEY_GPIO);
    if (val == FUNC_KEY_ON_VAL) {
        CalAreaAndDeep(1);
    } else {
        clean_gps_data(GPS_DATA_PATH);
        clean_gps_data(DEPTH_DATA_PATH);
        startDeepWorkInit();
    }

    while (threadRuning) {
        val = read_gpio(FUNCTION_KEY_GPIO);
        if (val == FUNC_KEY_ON_VAL) {
            if (gps_state == 0) { 
                if (gps_unposition_count%14 == 0) {//未定位，一直播放未定位语音,报警器响
                    write(threadSocketW, playMusic_CMD + UNPOSITIONED, sizeof(unsigned int));
                    write_gpio(ALARM_GPIO, 1);
                }
                gps_unposition_count++;
            } else {
                if (gps_unposition_count > 0) {//未定位->定位，播放一次已定位语音
                    write(threadSocketW, playMusic_CMD + POSITIONED, sizeof(unsigned int));
                    write_gpio(ALARM_GPIO, 0);
                }
                gps_unposition_count = 0;
            }
            if (start_deep_work == 0) {
                start_deep_work = 1;
                write_gpio(ALARM_GPIO, 0);
                LOGE("工作按钮:开");
                dArea = 0;//工作开才清零亩数显示，应为工作关时候要一直显示亩数
                ts = time(NULL);
                tm = localtime(&ts);
                sprintf(time_str, "开始时间:%d-%02d-%02d %02d:%02d:%02d\r\n", (1900+tm->tm_year), 1+tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
                write_log_to_sdcard(LOG_TXT_PATH, "工作按钮开,自动计算面积");
                write_gps_info("%s", "工作按钮开,自动计算面积");
              //  autoCalArea(getAutoDistance(0, 1));//工作按钮按下，开始计算上传自动面积;此处会调用startDeepWorkInit();
                if (gps_state)
                    write(threadSocketW, playMusic_CMD + POSITIONED, sizeof(unsigned int));
                write_gps_info("%s", time_str);
                generate_zip_pack();
            }
        } else {
            if (start_deep_work == 1) {
                start_deep_work = 0;
                LOGE("工作按钮:关");
                write_log_to_sdcard(LOG_TXT_PATH, "工作按钮:关");
                ts = time(NULL);
                tm = localtime(&ts);
                sprintf(time_str, "结束时间:%d-%02d-%02d %02d:%02d:%02d\r\n\r\n\r\n\r\n", (1900+tm->tm_year), 1+tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
                CalAreaAndDeep(0);
                write_gps_info("%s", time_str);
                generate_zip_pack();
            }
        }
        sleepMsec(500);
    }
    LOGE("线程%s退出", __func__);
    return NULL;
}

static unsigned int filter[10];
static int ultra_count = 0, sys_led_flags = 0;
static unsigned int ultra_err_count = 0, timer_count = 0;
volatile  int depth_invalid_count = 0;
static  int depth_led = 0;//深度不合格时候灯闪烁提示
static char deep_buf[32];
static int err_disp = ERROR, para_disp = BLACK;
extern int disp_set_para;
#define SENSOR_TYPE_A 1
#define SENSOR_TYPE_B 2

static int compInc(const void *a, const void *b) {  
    return *(int *)a - *(int *)b;  
}  

static int gen_average(unsigned int *ary, int len) {
    int i, sum = 0;
    for (i = 0; i < len; i++)
        sum += ary[i];

    return sum/len;
}

#define ARRAY_SIZE(x) sizeof(x)/sizeof(x[0])
unsigned int calDeep(void) {
    //char temp[5];
    // if(++g_calculationDistanceDelay_ms >= CALCULATION_PREIOD)
    //  {
    unsigned int i;
    //LOGE("Depth sample value:");
    //for (i = 0; i < ARRAY_SIZE(filter); i++)
    //    LOGE("%d", filter[i]);
    qsort(filter, ARRAY_SIZE(filter), sizeof(filter[0]), compInc);
    return gen_average(filter+3, 4);

}

static int check_sensor_b(void) {
    uint16_t data[1];
    int16_t data1;
    double angle;
    int rc; 
    int height;

    //return 0;
    rc = modbus_read(0x3e, 1, data);
    if (rc == 1) {
        data1 = (int16_t)data[0];
        angle = data1/32768.0*PI;
        height = SysInfor.a_sensor_height*(sin(SysInfor.angle*PI/180) - sin(angle));
        LOGE("角度传感器通讯成功,角度=%f,高度=%d", data1*180/32768.0, height);
        write_log_to_sdcard(LOG_TXT_PATH, "B型传感器");
        return SENSOR_TYPE_B;
    }
    return 0;
}

static int check_sensor_a(void) {
   // TriggerUltrasonic();//触发
    if (ultra_uart_data > 0) {
        write_log_to_sdcard(LOG_TXT_PATH, "A型传感器");
        LOGE("A型传感器");
        return SENSOR_TYPE_A;
    }
    return 0;
}

#define DEBOUNCE_TOL 500
static void ultra_calc(unsigned int time) {
    unsigned int distance;
    
    distance = time / 43.5;

    if (distance <= 5 || distance > MAX_DISTANCE)
        return;
    distance += 150;  //距离校正
    //LOGE("ultra_count=%d, distance=%d", ultra_count, distance);
    if (ultra_count>0 && abs(filter[ultra_count-1]-distance)<DEBOUNCE_TOL) {
        //LOGE("distance=%d", distance);
        filter[ultra_count++] = distance;
        return;
    }
    ultra_count = 1;
    filter[0] = distance;
}

static void *UltraTimer(void *arg) {
    uint16_t data[1];
    int16_t data1;
    int rc; 
    double angle;
    int height;
    int sensor_type = 0;
    struct timeval tv, tv_ultra;
    int  g_delayOfUltrasonic;
	int while_count = 0;

    sleepMsec(5000);
    gettimeofday(&tv, (struct timezone *) NULL);
    while (threadRuning) {
        if (sensor_type == SENSOR_TYPE_B) {
            rc = modbus_read(0x3e, 1, data);
            data1 = (int16_t)data[0];
            if (rc == 1) {
                ultra_err_count = 0;
                angle = data1/32768.0*PI;
                height = SysInfor.a_sensor_height*(sin(SysInfor.angle*PI/180) - sin(angle));
                //LOGE("angle=%d h=%d", data1*180/32768, height);
                if (height > 0 && height < 399) {
                    filter[ultra_count] = height;
                    ultra_count++;
                }
            } else {
                ultra_err_count++;
            }
        } else if (sensor_type == SENSOR_TYPE_A) {//SENSOR_TYPE_A
           // TriggerUltrasonic();//触发
             g_delayOfUltrasonic = ultra_uart_data;//得到时间
             //LOGE("ultra time=%d", g_delayOfUltrasonic);
             if (g_delayOfUltrasonic >= 0) {//超声波距离很近时候后单片机返回0，移动探头数据不稳定时候单片机返回0
                 ultra_err_count = 0;
                 if(g_delayOfUltrasonic > 0 ) 
                     ultra_calc(g_delayOfUltrasonic);
             } else {
                ultra_err_count++;
             }
        } else {//sensor错误，重新检测sensor类型
            g_depth = 0;
            gettimeofday(&tv_ultra, (struct timezone *) NULL);
            int time_diff = abs(SEC_DIFF(tv, tv_ultra));
            //LOGE("time_diff=%d", time_diff);
            if ((ultra_err_count >= 50) && ((ultra_err_count%25) == 0) && (time_diff < 30)) {
                write(threadSocketW, playMusic_CMD + SENSOR_ERR, sizeof(unsigned int));
                //LOGE("play sensor_err");
                sensor_type = 0;
            }
            if ((sensor_type=check_sensor_a()) || (sensor_type=check_sensor_b())) {
                ultra_err_count = 0;
                write(threadSocketW, playMusic_CMD + (sensor_type==SENSOR_TYPE_A ? ULTRA_OK:ANGLE_OK), sizeof(unsigned int));
            }
            ultra_err_count++;
        }

        /*if (ultra_count >= 10) {
            ultra_count = 0;
            ultra_depth = calDeep();*/
		if (while_count >= 10) {
			while_count = 0;
			if (ultra_count > 0)
			{
				ultra_depth = gen_average(filter, ultra_count);
				ultra_count = 0;
			}
			if (sensor_type == SENSOR_TYPE_A) {
				g_depth = (ultra_depth > SysInfor.ref_depth) ? 0 : SysInfor.ref_depth - ultra_depth;
			}
			else {
				g_depth = ultra_depth;
			}
			if (g_depth > 398) {
				g_depth = 363;
			}
			else if (g_depth < 0)
			{
				g_depth = 0;
			}
			LOGE("ultra_depth:%d, g_depth=%d", ultra_depth, g_depth);
            if (g_depth>=150) {//深度大于150小于400毫米才保存
                if (g_depth > SysInfor.depth) {
                    depth_invalid_count = 0;
                    depth_led = 0;
                } else {
                    depth_led = 1;
                }
                if ((start_deep_work || gps_speed > 1)&&(totalDepthCount < GPS_MAX_DATA)) {//自动和手动测亩都需要深度信息
                    stru_GPSPOINT gps;
                    memset(&gps, 0, sizeof(gps));
                    gps.depth = g_depth;
                    depth_offline_data[totalDepthCount++] = gps;
                    save_depth_data(DEPTH_DATA_PATH, &gps);
                }
            } else {
                depth_led = 1;
            }
			depth_invalid_count++;
            if (start_deep_work && depth_led && (depth_invalid_count > 5 && depth_invalid_count < 20)) {//无效数据语音播报15s
				write(threadSocketW, playMusic_CMD + DEPTH_INVALID, sizeof(unsigned int));
			}

            if (start_deep_work == 0)
                depth_invalid_count = 0;
        }
        //LOGE("led=%d,depth=%d,default_deep=%d, ref_depth=%d", depth_led, g_depth, default_deep,  default_ref_depth);
        //LOGE("start_deep_work=%d", start_deep_work);
        if (disp_set_para) {
            if (disp_set_para++ > 50)
                disp_set_para = 0;
            if (timer_count%3 == 0)
                para_disp = (para_disp==BLACK) ? MIN(SysInfor.ref_depth, 9999) : BLACK; //BLACK->LED全黑
        }
        //int area_disp = MIN(dArea*10, 9999);
		int area_disp = MIN(walk_area < dArea ? walk_area * 10 : dArea * 10, 9999);
        if (ultra_err_count == 50) {
            sensor_type = -1;
        }
        if (sensor_type > 0)
            gettimeofday(&tv, (struct timezone *) NULL);
        write_led(disp_set_para?para_disp:sensor_type==0?err_disp:start_deep_work?g_depth:area_disp, sys_led_flags, gps_state, flag_login, start_deep_work?depth_led:0);

        if((timer_count++ % 3) == 0) {
            err_disp = (err_disp==ERROR)?BLACK:ERROR;//ERROR->LED 4个E
            if (check_tvin() == 1) {
                sys_led_flags = !sys_led_flags;
                tvin_state = 1;
            } else { 
                tvin_state = 0;
                sys_led_flags = 1;
            }
        }
		while_count++;
        sleepMsec(100);
    }

    LOGE("线程%s退出", __func__);
    return NULL;
}

static pthread_t ntid[6];
void os_sys_init() {
    int ret;
    //pthread_attr_t attr; 

    //pthread_attr_init (&attr);
   // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    //UltraThread();
    ret = pthread_create(&ntid[0], NULL, SupplementOilAndReportLocation, NULL);//注册，鉴权，心跳，位置信息，测亩信息
    ret = pthread_create(&ntid[1], NULL, thread_play_music, NULL);//保存GPS信息到SDCARD/USB
    ret = pthread_create(&ntid[2], NULL, UltraTimer, NULL);
    ret = pthread_create(&ntid[3], NULL, function_key_state, NULL);
    ret = pthread_create(&ntid[4], NULL, read_para, NULL);//读取SDCARD/USB参数

}

static void handle_pipe(int sig) {
    LOGE("捕获到内核发送网络异常信号");
}


int main (void) {
    int ret;
    pthread_t thread_gps, thread_ultra_uart;

    memset(gpsdata.gps_data, 0, sizeof(gpsdata.gps_data));
    strcpy((char *)gpsdata.gps_data, GPS_DATA_BUF); //fix data parser NULL bug
    str_gpsPoints = (stru_GPSPOINT *)malloc(sizeof(stru_GPSPOINT) * GPS_MAX_DATA);
    str_PlanarPoints = (stru_GPSPOINT *)malloc(sizeof(stru_GPSPOINT) * GPS_MAX_DATA);
    str_outLinePoints = (stru_GPSPOINT *)malloc(sizeof(stru_GPSPOINT) * GPS_MAX_DATA);
    depth_offline_data = (stru_GPSPOINT *)malloc(sizeof(stru_GPSPOINT) * GPS_MAX_DATA);
    //signal(SIGIO, tvin_signal);
    int fd = openUltra();
    open_led();
    fcntl(fd, F_SETOWN, getpid());
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);
    openUltraUart("/dev/ttyHSL1", 0);

   // LOGE("sizeof(1LL)=%d sizeof(long)=%d, sizeof(long long)=%d", sizeof(1LL), sizeof(long), sizeof(long long));
    if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, threadSocketFd ) < 0 ) {
        LOGE("could not create thread control socket pair: %s", strerror(errno));
    }
    threadSocketR = threadSocketFd[1];
    threadSocketW = threadSocketFd[0];
    device_init();

    //pthread_attr_t attr; 
    //struct sched_param param;
    //pthread_attr_init (&attr);
    //pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    ret = pthread_create(&thread_gps, NULL, gps_state_init, NULL);
    ret = pthread_create(&thread_ultra_uart, NULL, readUltraUart, NULL);//读取SDCARD/USB参数

    struct sigaction action;
    action.sa_handler = handle_pipe;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGPIPE, &action, NULL);
    GetAuthenticationCode();//从存储芯片中提取鉴权码

    //write_led(SysInfor.version/10, 0, 0, 0, 0);
    write_led(app_version/10, 0, 0, 0, 0);
    sleepMsec(5000);

    os_sys_init();
    void *result;
    pthread_join(thread_gps, &result);
    //pthread_join(ntid[0], NULL);
    //pthread_join(ntid[2], NULL);
    //pthread_join(ntid[3], NULL);
    LOGE("所有线程退出，进入测试模式");
    while (1) {
        if (!threadRuning) {
            struct tm *p;
            long ts;
            int result = 0;

            LOGE("开始测试");
            ts = time(NULL);
            p = localtime(&ts);
            write_gps_info("%d-%02d-%02d %02d:%02d:%02d 进入工厂生产测试模式", (1900+p->tm_year), 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
            write_led(LED_TEST, 1, 1, 1, 1);
            write(threadSocketW, playMusic_CMD + TEST_START, sizeof(unsigned int));
            sleepMsec(2000);
            if (!gps_factory_test()) {
                write(threadSocketW, playMusic_CMD + GPS_ERROR, sizeof(unsigned int));
                write_gps_info("%s", "GPS异常");
                sleepMsec(2000);
                result = -1;
            }
            if (NetIsOk("www.qq.com") == false && NetIsOk("www.baidu.com") == false) {
                write(threadSocketW, playMusic_CMD + NETWORK_ERROR, sizeof(unsigned int));
                write_gps_info("%s", "4G异常");
                sleepMsec(2000);
                result = -1;
            }
            int i, type = 0;
            for (i = 0; i < 10; i++) {
                type = check_sensor_a();
                type |= check_sensor_b();
                if (type)
                    break;
            }
            if (!type) {
                write(threadSocketW, playMusic_CMD + ULTRA_ERROR, sizeof(unsigned int));
                write_gps_info("%s", "传感器异常");
                sleepMsec(2000);
                result = -1;
            }

            if (access("/dev/video1", F_OK) || (check_tvin() == 0)) {
                write(threadSocketW, playMusic_CMD + CAMERA_ERROR, sizeof(unsigned int));
                write_gps_info("%s", "摄像头异常");
                sleepMsec(2000);
                result = -1;
            }

            if (result == 0) {
                write(threadSocketW, playMusic_CMD + TEST_OK, sizeof(unsigned int));
                write_gps_info("%s", "测试通过");
            }
            threadRuning = 1;
        }
        sleep(2);
    }
    close_led();
    close_gpio();
    closeUltraUart();
    free(str_gpsPoints);
    free(str_PlanarPoints);
    free(str_outLinePoints);
    free(depth_offline_data);

    return 0;
}

